package com.yyfax.pay.common.util;

import com.alibaba.fastjson.annotation.JSONField;
import com.fuiou.util.MD5;
import com.yyfax.framework.model.Content;
import com.yyfax.pay.common.annotation.FuiouSign;
import com.yyfax.pay.third.model.to.fuioudeposit.FuiouQueryTransferChargeReq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;

/**
 * 富友签名工具类
 * 
 * @author heizq
 * @date 2017-05-16 16:55:18
 * @since v1.2.0
 */
public class FuiouSignUtil {

	private static Logger logger = LoggerFactory.getLogger(FuiouSignUtil.class);

	/**
	 * 生成富友签名
	 * 
	 * @author heizq
	 * @date 2017-05-16 16:55:37
	 * @since v1.2.0
	 * @param signContent 签名实体
	 * @param screatKey 签名密钥
	 * @return
	 */
	public static <T extends Object> String createFuiouSign(T signContent, String screatKey) {
		FuiouSign sign = signContent.getClass().getAnnotation(FuiouSign.class);
		String[] fields = sign.signField();
		StringBuilder signStr = new StringBuilder();
		for (String field : fields) {
			signStr.append(getFieldValueByName(field, signContent)).append("|");
		}
		signStr.append(screatKey);
		logger.info("生成的签名字符串为：{}", signStr.toString());
		return MD5.MD5Encode(signStr.toString());
	}

	/**
	 * 校验富友签名
	 * 
	 * @author heizq
	 * @date 2017-05-16 16:56:32
	 * @since v1.2.0
	 * @param signContent 校验的签名实体
	 * @param signValue 校验的签名
	 * @param screatKey 密钥key
	 * @return
	 */
	public static <T extends Content> boolean checkFuiouSign(T signContent, String signValue, String screatKey) {
		try {
			FuiouSign sign = signContent.getClass().getAnnotation(FuiouSign.class);
			String[] fields = sign.signField();
			StringBuilder signStr = new StringBuilder();
			for (String field : fields) {
				signStr.append(getFieldValueByName(field, signContent)).append("|");
			}
			signStr.append(screatKey);
			logger.info("验证的签名字符串为：{}", signStr.toString());
			if (MD5.MD5Encode(signStr.toString()).equals(signValue)) {
				return true;
			}
		} catch (Exception e) {
			logger.error("校验富友签名失败，signContent：" + signContent.toString(), e);
		}
		return false;
	}

	/**
	 * 根据属性名获取属性值
	 */
	private static Object getFieldValueByName(String fieldName, Object c) {
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getter = "get" + firstLetter + fieldName.substring(1);
			Method method = c.getClass().getMethod(getter, new Class[] {});
			Object value = method.invoke(c, new Object[] {});
			return value;
		} catch (Exception e) {
			logger.error("根据属性名获取属性值失败，属性名：" + fieldName, e);
			return null;
		}
	}

	/**
	 * 生成富友转账充值查询的签名
	 *
	 * @author wujiande
	 * @date 2018-05-25 11:30:00
	 * @since v2.1.7
	 *
	 * @param req
	 * @param key
	 * @return
	 */
	public static String createFuiouSignForQueryTransferCharge(FuiouQueryTransferChargeReq req, String key) {
		Field[] fields = FuiouQueryTransferChargeReq.class.getDeclaredFields();
		Arrays.sort(fields, new Comparator<Field>() {
			@Override
			public int compare(Field o1, Field o2) {
				return o1.getAnnotation(JSONField.class).name().compareTo(o2.getAnnotation(JSONField.class).name());
			}
		});
		StringBuilder signStr = new StringBuilder();
		for(Field field : fields) {
			if(field.getAnnotation(Transient.class)==null) {
				Object fieldName = getFieldValueByName(field.getName(), req);
				fieldName = fieldName == null ? "" : fieldName;
				signStr.append(fieldName).append("|");
			}
		}
		signStr.append(key);
		logger.info("生成的签名字符串为：{}", signStr.toString());
		return MD5.MD5Encode(signStr.toString());
	}

	/**
	 * 校验富友转账充值查询的签名
	 *
	 * @author wujiande
	 * @date 2018-05-22 13:54:51
	 * @since v2.1.7
	 *
	 * @param plainStr
	 * @param signValue
	 * @param screatKey
	 * @return
	 */
	public static boolean checkFuiouSignForQueryTransferCharge(String plainStr, String signValue, String screatKey) {
		StringBuilder signStr = new StringBuilder(plainStr);
		signStr.append("|").append(screatKey);
		logger.info("验证的签名字符串为：{}", signStr.toString());
		try {
			if(MD5.MD5Encode(signStr.toString()).equals(signValue)) {
				return true;
			}
		} catch (Exception e) {
			logger.error("校验富友签名失败，signContent：" + signStr.toString(), e);
		}
		return false;
	}

}
